package com.ultron.app.config.securityAuthentication.filter;

import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;

import com.ultron.app.config.securityAuthentication.entity.UserContextHolder;
import com.ultron.app.modules.user.entity.auth.AuthBaseVO;
import com.ultron.app.util.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

/**
 * 标题：身份验证过滤器
 * 说明：身份验证过滤器，根据请求中的jwt信息解析用户个人信息并保存到线程
 * 时间：2023/3/17
 * 作者：admin
 */
@WebFilter(
        filterName = "AuthenticationFilter",
        urlPatterns = {"/*"}
)
@Order(1)
@Slf4j
public class AuthenticationFilter implements Filter {

    /**
     * Token名称
     */
    @Value("${access-token-name}")
    private String accessTokenName;

    /**
     * 万能Key
     */
    @Value("${master-key}")
    private String masterKey;

    /**
     * JWT KEY
     */
    @Value("${jwt-key}")
    private String jwtKey;

    /**
     * 白名单列表
     */
    @Value("${white-uris}")
    private  String[] WHITE_URIS;




    @Override
    public void init(FilterConfig filterConfig) {


    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("=============进入认证过滤器=============");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String reqUri = request.getRequestURI();
        log.info("请求====》"+reqUri);

        //请求token
        String token = request.getHeader(accessTokenName);
        //token为空，校验是否白名单
        if (StringUtils.isBlank(token)) {
            boolean permission = this.isPermission(request);
            if(permission){
                filterChain.doFilter(servletRequest, servletResponse);
            }else {
                PermissionExceptionResponse.rsp(response);
            }

        } else {
            if (token.equals(masterKey)){
                filterChain.doFilter(servletRequest, servletResponse);

            }else {
                JWT jwt = JWTUtil.parseToken(token);
                JWTPayload payload = jwt.getPayload();
                AuthBaseVO authBaseVO = JSONUtil.toBean(payload.getClaimsJson(), AuthBaseVO.class);
                Date expireTime = authBaseVO.getExpireTime();
                //过期控制
                if (expireTime.compareTo(DateUtils.getCurrentDateYYYYMMDDHHMMSS()) > 0) {
                    //保存到线程
                    UserContextHolder.holder.set(authBaseVO);
                    filterChain.doFilter(servletRequest, servletResponse);
                } else {
                    PermissionExceptionResponse.rsp(response);
                }
            }

        }
        //清理线程中的用户信息
        UserContextHolder.remove();
        log.info("=============完成认证过滤器=============");
    }


    /**
     * 是否有权限访问
     * @param request
     * @return
     */
    private boolean isPermission(HttpServletRequest request){
        boolean rsp = false;
        String reqUri = request.getRequestURI();
        String method = request.getMethod();
        AntPathMatcher pathMatcher = new AntPathMatcher();
        //OPTIONS请求或白名单内允许
        if("OPTIONS".equals(method)){
            rsp = true;
        }else {
            for(String whiteUri:this.WHITE_URIS){
                //1、白名单放行:pathMatcher.match("/api/uaa/**", reqUrl)
                if (pathMatcher.match(whiteUri, reqUri)) {
                    rsp = true;
                    break;
                }
            }
        }


        return rsp;
    }




    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}
